package org.eden.heartbeat.core.persistence.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eden.heartbeat.api.model.Request;
import org.eden.heartbeat.core.persistence.RequestDAO;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * The DAO implementation for status requests sent to remote machines.
 *
 * @author trsimoes
 * @version $Revision:$
 */
public class RequestDAOImpl extends AbstractDAOImpl implements RequestDAO {

    private static Log LOG = LogFactory.getLog(RequestDAOImpl.class);

    private PreparedStatement insertPreparedStatement;

    private final static String INSERT_SQL = "INSERT INTO REQUEST (HOST, PORT, DATE, RESULT) values (?, ?, ?, ?)";

    private final static String GET_OFFLINE_TIME_SQL = "SELECT ID, HOST, PORT, DATE, RESULT FROM REQUEST WHERE HOST=? " +
            "AND PORT=?";

    private final static String COUNT_OFFLINE_PERIODS_SQL = "SELECT COUNT(ID) FROM REQUEST WHERE HOST=? AND PORT=?";

    @Override
    public void insert(Request request) throws SQLException {

        try {
            if (this.insertPreparedStatement == null) {
                // create insert prepared statement
                this.insertPreparedStatement = this.persistenceManager.getConnection().prepareStatement(INSERT_SQL);
            }

            this.insertPreparedStatement.setString(1, request.getHost());
            this.insertPreparedStatement.setInt(2, request.getPort());
            this.insertPreparedStatement.setTimestamp(3, new Timestamp(request.getDate().getTime()));
            this.insertPreparedStatement.setBoolean(4, request.isResult());

            this.insertPreparedStatement.executeUpdate();
        } catch (SQLException e) {
            if (LOG.isErrorEnabled()) {
                LOG.error("error inserting request in database", e);
            }
            if (this.insertPreparedStatement != null) {
                this.insertPreparedStatement.close();
            }
        }
    }

    @Override
    public List<Request> findRequestBetweenDates(String host, int port, Date startDate, Date endDate) throws SQLException {

        ResultSet resultSet = null;
        PreparedStatement queryPreparedStatement = null;

        try {
            String query = GET_OFFLINE_TIME_SQL;

            // update query
            if (startDate != null) {
                query += " AND DATE >= ?";
            }
            if (endDate != null) {
                query += " AND DATE <= ?";
            }

            queryPreparedStatement = this.persistenceManager.getConnection().prepareStatement(query);
            queryPreparedStatement.setString(1, host);
            queryPreparedStatement.setInt(2, port);
            if (startDate != null) {
                queryPreparedStatement.setTimestamp(3, new Timestamp(startDate.getTime()));
                if (endDate != null) {
                    queryPreparedStatement.setTimestamp(4, new Timestamp(endDate.getTime()));
                }
            } else {
                if (endDate != null) {
                    queryPreparedStatement.setTimestamp(3, new Timestamp(endDate.getTime()));
                }
            }

            resultSet = queryPreparedStatement.executeQuery();

            List<Request> requestList = new ArrayList<Request>();

            while (resultSet.next()) {
                // create Request object
                Request request = new Request();
                request.setId(resultSet.getLong("ID"));
                request.setHost(resultSet.getString("HOST"));
                request.setPort(resultSet.getInt("PORT"));
                request.setDate(resultSet.getTimestamp("DATE"));
                request.setResult(resultSet.getBoolean("RESULT"));

                requestList.add(request);
            }

            return requestList;
        } catch (SQLException e) {
            if (LOG.isErrorEnabled()) {
                LOG.error("error communicating with database", e);
            }
            throw e;
        } finally {
            // close resources
            if (resultSet != null) {
                resultSet.close();
            }
            if (queryPreparedStatement != null) {
                queryPreparedStatement.close();
            }
        }
    }

    @Override
    public void shutdown() throws SQLException {
        if (this.insertPreparedStatement != null) {
            this.insertPreparedStatement.close();
        }
    }
}